package library;

import java.awt.print.Printable;
import java.rmi.server.ExportException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import db.LibraryDb;
import dom.AdminAccount;
import dom.Book;
import dom.BookReservation;
import dom.EducationalSystemEnum;
import dom.StudentAccount;

public class Library {

	private EducationalSystemEnum edu;
	//private HashMap<String,List<StudentAccount>> accounts = null;
	//private List<Book> books = null;
	//private List<BookReservation> bookReservations = null;
	private List<AdminAccount> admins = null;
	private LibraryUtil util = new LibraryUtil();
	private LibraryDb libraryDb = null;
	private String libraryId = "";
	
	public Library(EducationalSystemEnum edu, String libraryId) throws Exception {
		this.edu = edu;
		String tmpLibraryId = libraryId + "." +  edu.toString().toLowerCase();
		this.libraryId = tmpLibraryId;
		 libraryDb = new LibraryDb(tmpLibraryId);
		//this.accounts = libraryDb.getAccounts();
		//this.books = libraryDb.getBooks();
		//libraryDb.saveBooks();
		//libraryDb.saveAccounts();
		 
		 // create admin
		 AdminAccount adminAccount1 = new AdminAccount("admin", "admin");
		 this.admins = new ArrayList<AdminAccount>();
		 this.admins.add(adminAccount1);
	}
	
	public void addStudentAccount(StudentAccount sa) throws Exception {
		HashMap<String,List<StudentAccount>> accounts = getAccounts();
		this.util.addStudentAccountToAccountList(sa, accounts);
		exportAccounts(accounts);
	}

	public EducationalSystemEnum getEducationalInstitution() {
		return edu;
	}
	
	public String getEducationalInstitutionString() {
		if(edu != null){
			return edu.toString();
		}
		return "";
	}

	public void setEdu(EducationalSystemEnum edu) {
		this.edu = edu;
	}

	public HashMap<String, List<StudentAccount>> getAccounts() {
		return libraryDb.getAccounts();
	}

	public List<Book> getBooks() {
		return libraryDb.getBooks();
	}

	public List<BookReservation> getBookReservations() {
		HashMap<String,List<StudentAccount>> accounts = getAccounts();
		
		List<BookReservation> bookReservations = new ArrayList<BookReservation>();
		for(String studentKey : accounts.keySet()){
			List<StudentAccount> studentAccounts = accounts.get(studentKey);
			for(StudentAccount studentAccount : studentAccounts){
				bookReservations.addAll(studentAccount.getBookResevations());
				// This is kind of a hack
				for(BookReservation bookReservation : studentAccount.getBookResevations()){
					bookReservation.setStudentAccount(studentAccount);
				}
			}
			
		}
		return bookReservations;
	}

	public List<AdminAccount> getAdmins() {
		return admins;
	}

	public void setAdmins(List<AdminAccount> admins) {
		this.admins = admins;
	}
	
	public Book getBookByName(String name){
		List<Book> books = getBooks();
		//name = name.trim();
		for(Book book : books){
			if(name.equalsIgnoreCase(book.getName())){
				return book;
			}
		}
		return null;
	}
	
	public List<Book> getBooksByAuthor(String name){
		List<Book> booksFromDB = getBooks();
		List<Book> books = new ArrayList<Book>();
		for(Book book : booksFromDB){
			if(name.equals(book.getName())){
				books.add(book);
			}
		}
		return books;
	}
	
	public synchronized List<BookReservation> getNonReturners() {
		System.out.print("getNonReturners() : " + libraryId);
		List<BookReservation> nonReturners = new ArrayList<BookReservation>();	
		List<BookReservation> bookReservations = getBookReservations();
		for(BookReservation bookReservation : bookReservations){
			if(bookReservation.isOverdue()){
				bookReservation.setFeesDue(bookReservation.getLateFees());
				nonReturners.add(bookReservation);
			}
		}
		return nonReturners;
	}
	
	public List<StudentAccount> createUnifiedStudentList(HashMap<String,List<StudentAccount>> accountStructure){
		List<StudentAccount> accounts = new ArrayList<StudentAccount>();
		
		for(String key : accountStructure.keySet()){
			accounts.addAll(accountStructure.get(key));
		}
		
		return accounts;
	}
	
	public String listBookReservations(){
		
		StringBuilder sb = new StringBuilder();
		for(BookReservation br : getBookReservations()){
			sb.append(br.toString() + "\n");
		}
		return sb.toString();
	}
	
	public String getNonReturnersString(){
		
		List<BookReservation> overdueBookReservations = getNonReturners();
		
		StringBuilder sb = new StringBuilder();
		
		if(overdueBookReservations == null || overdueBookReservations.isEmpty()){
			//sb.append("There are no overdue books!");
			sb.append("");
			return sb.toString();
		}
		
		// Sort overdue reservations by educational institution
		HashMap<EducationalSystemEnum,List<BookReservation>> sortedReservations = new HashMap<EducationalSystemEnum, List<BookReservation>>();
		for(BookReservation overdueBookReservation : overdueBookReservations){
			if(sortedReservations.get(overdueBookReservation.getStudentAccount().getEdu()) == null){
				sortedReservations.put(overdueBookReservation.getStudentAccount().getEdu(), new ArrayList<BookReservation>());
			}
			sortedReservations.get(overdueBookReservation.getStudentAccount().getEdu()).add(overdueBookReservation);
		}
		
		for(EducationalSystemEnum key : sortedReservations.keySet()){
			List<BookReservation> brs = sortedReservations.get(key);
			sb.append("-----------------------------------------------------------\n");
			sb.append(brs.get(0).getStudentAccount().getEdu().toString() + ": \n");
			sb.append("-----------------------------------------------------------\n");
			for(BookReservation br : brs){
				if(br.getDaysOverdue() > 0){
					sb.append(br.getStudentAccount().getFirstName() + "\t");
					sb.append(br.getStudentAccount().getLastName() + "\t");
					sb.append(br.getStudentAccount().getPhoneNumber() + "\t");
					sb.append(br.getDaysOverdue() + " days overdue\t");
					sb.append(br.getFeesDue() + " $ due");
					sb.append("\n");
				}
			}
			sb.append("-----------------------------------------------------------\n\n");
		}
		return sb.toString();
	}

	public StudentAccount getAccountByUsername(String username){
		
		if(username.isEmpty()){
			return null;
		}
		
		HashMap<String,List<StudentAccount>> accounts = getAccounts();
		String key = username.substring(0,1);
		//System.out.println("using key: '" + key + "'");
		List<StudentAccount> theAccounts = accounts.get(key);
		if(theAccounts != null && !theAccounts.isEmpty()){
			for (StudentAccount studentAccount : theAccounts){
				if(studentAccount.getUsername().equalsIgnoreCase(username)){
					return studentAccount;
				}
			}
		}
		return null;
	}
	
	public boolean hasCopiesOfBook(String bookName, String authorName){
		List<Book> books = getBooks();
		for(Book book : books){
			if(book.getName().equalsIgnoreCase(bookName)){
				if(book.getCopies() > 0){
					return true;
				}
			}
		}
		return false;
	}
	
	public void saveAccounts(){
		libraryDb.saveAccounts();
	}
	
	public void saveBooks(){
		libraryDb.saveBooks();
	}
	
	public void exportAccounts(HashMap<String,List<StudentAccount>> accounts){
		libraryDb.exportAccounts(accounts);
	}
	
	public void exportBooks(List<Book> books){
		libraryDb.exportBooks(books);
	}
	
	/**
	 * Destroy the database entirely.
	 * Only used in simulating failure
	 */
	public void nullifyDatabase() {
		HashMap<String,List<StudentAccount>> tmpAcc = new HashMap<String,List<StudentAccount>>();
		List<Book> books = new ArrayList<Book>();
		libraryDb.exportAccounts(tmpAcc);
		libraryDb.exportBooks(books);
	}
}
